﻿namespace Catel.Articles._08___WP7_Camera.ViewModels
{
    using System.Collections.Generic;
    using System.Windows.Media.Imaging;
    using Catel.Data;
    using MVVM;
    using Data;
    using MVVM.Services;

    /// <summary>
    /// UserControl view model.
    /// </summary>
    public class PhotoViewModel : ViewModelBase
    {
        #region Variables
        private int _currentIndex;
        #endregion

        #region Constructor & destructor
        /// <summary>
        /// Initializes a new instance of the <see cref="PhotoViewModel"/> class.
        /// </summary>
        public PhotoViewModel()
        {
            Flick = new Command<FlickData>(OnFlickExecute, OnFlickCanExecute);
            GoToCamera = new Command(OnGoToCameraExecute);
            Delete = new Command(OnDeleteExecute);
            About = new Command(OnAboutExecute);
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the title of the view model.
        /// </summary>
        /// <value>The title.</value>
        public override string Title { get { return "Picture preview"; } }

        /// <summary>
        /// Gets the photo repository.
        /// </summary>
        /// <value>The photo repository.</value>
        private IPhotoRepository PhotoRepository { get { return GetService<IPhotoRepository>(); } }

        /// <summary>
        /// Gets the photo.
        /// </summary>
        public BitmapSource Photo
        {
            get { return GetValue<BitmapSource>(PhotoProperty); }
            set { SetValue(PhotoProperty, value); }
        }

        /// <summary>
        /// Register the Photo property so it is known in the class.
        /// </summary>
        public static readonly PropertyData PhotoProperty = RegisterProperty("Photo", typeof(BitmapSource));
        #endregion

        #region Commands
        /// <summary>
        /// Gets the GoToCamera command.
        /// </summary>
        public Command GoToCamera { get; private set; }

        /// <summary>
        /// Method to invoke when the GoToCamera command is executed.
        /// </summary>
        private void OnGoToCameraExecute()
        {
            var navigationService = GetService<INavigationService>();
            navigationService.Navigate<MainPageViewModel>();
        }

        /// <summary>
        /// Gets the Delete command.
        /// </summary>
        public Command Delete { get; private set; }

        /// <summary>
        /// Method to invoke when the Delete command is executed.
        /// </summary>
        private void OnDeleteExecute()
        {
            var messageService = GetService<IMessageService>();
            if (messageService.Show("Are you sure you want to delete the image?", "Delete image?", MessageButton.OKCancel) == MessageResult.Cancel)
            {
                return;
            }

            PhotoRepository.Photos.RemoveAt(_currentIndex);

            var navigationService = GetService<INavigationService>();
            var navigationArguments = new Dictionary<string, object>();

            if (PhotoRepository.Photos.Count == 0)
            {
                navigationService.Navigate<MainPageViewModel>();
            }
            else
            {
                navigationArguments.Add("id", (_currentIndex == 0) ? 0 : _currentIndex - 1);
                navigationService.Navigate<PhotoViewModel>(navigationArguments);
            }
        }

        /// <summary>
        /// Gets the Flick command.
        /// </summary>
        public Command<FlickData> Flick { get; private set; }

        /// <summary>
        /// Method to invoke when the Flick command can execute state is retrieved.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        /// <returns></returns>
        private bool OnFlickCanExecute(FlickData parameter)
        {
            if (parameter == null)
            {
                return true;
            }

            if (parameter.HorizontalVelocity > 0)
            {
                // Left always allowed
                return true;
            }

            if (parameter.HorizontalVelocity < 0)
            {
                if (_currentIndex + 1 < PhotoRepository.Photos.Count)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Method to invoke when the Flick command is executed.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        private void OnFlickExecute(FlickData parameter)
        {
            var navigationService = GetService<INavigationService>();
            var navigationArguments = new Dictionary<string, object>();

            if (parameter.HorizontalVelocity > 0)
            {
                // Left, always allowed
                if (_currentIndex <= 0)
                {
                    navigationService.Navigate<MainPageViewModel>();
                    return;
                }

                navigationArguments.Add("id", _currentIndex - 1);
                navigationService.Navigate<PhotoViewModel>(navigationArguments);
            }

            if (parameter.HorizontalVelocity < 0)
            {
                // Right
                if (_currentIndex + 1 < PhotoRepository.Photos.Count)
                {
                    navigationArguments.Add("id", _currentIndex + 1);
                    navigationService.Navigate<PhotoViewModel>(navigationArguments);
                }
            }
        }

        /// <summary>
        /// Gets the About command.
        /// </summary>
        public Command About { get; private set; }

        /// <summary>
        /// Method to invoke when the About command is executed.
        /// </summary>
        private void OnAboutExecute()
        {
            var navigationService = GetService<INavigationService>();
            navigationService.Navigate<AboutViewModel>();
        }
        #endregion

        #region Methods
        /// <summary>
        /// Called when the navigation has completed.
        /// </summary>
        /// <remarks>
        /// This should of course be a cleaner solution, but there is no other way to let a view-model
        /// know that navigation has completed. Another option is injection, but this would require every
        /// view-model for Windows Phone 7 to accept only the navigation context, which has actually nothing
        /// to do with the logic.
        /// <para/>
        /// It is also possible to use the <see cref="E:Catel.MVVM.ViewModelBase.NavigationCompleted"/> event.
        /// </remarks>
        protected override void OnNavigationCompleted()
        {
            _currentIndex = 0;

            if (NavigationContext.ContainsKey("id"))
            {
                int.TryParse(NavigationContext["id"], out _currentIndex);
            }

            Photo = PhotoRepository.Photos[_currentIndex];
        }
        #endregion
    }
}
